package com.gjy.util.encryption.sm.sm4;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * @author gjy
 * @version 1.0
 * @since 2025-07-07 15:39:11
 */
public class Sm4 {

    private static Invocable invocable = null;

    public static String encrypt(String msg, String key, Sm4Options sm4Options) {
        if (msg != null && !msg.trim().isEmpty()) {
            String encryptData = null;

            try {
                encryptData = (String) invocable.invokeFunction("encrypt", new Object[]{msg, key, getOptionsMap(sm4Options)});
            } catch (NoSuchMethodException | ScriptException var5) {
                var5.printStackTrace();
            }

            return encryptData;
        } else {
            return "";
        }
    }

    public static String encrypt(String msg, String key) {
        return encrypt(msg, key, null);
    }

    public static String decrypt(String encryptData, String key, Sm4Options sm4Options) {
        if (encryptData != null && !encryptData.trim().isEmpty()) {
            String decryptData = null;

            try {
                decryptData = (String) invocable.invokeFunction("decrypt", new Object[]{encryptData, key, getOptionsMap(sm4Options)});
            } catch (NoSuchMethodException | ScriptException var5) {
                var5.printStackTrace();
            }

            return decryptData;
        } else {
            return "";
        }
    }

    public static String decrypt(String encryptData, String key) {
        return decrypt(encryptData, key, null);
    }

    public static byte[] hexToBytes(String hex) {
        int length = hex.length();
        byte[] result;
        if (length % 2 == 1) {
            ++length;
            result = new byte[length / 2];
            hex = "0" + hex;
        } else {
            result = new byte[length / 2];
        }

        int j = 0;

        for (int i = 0; i < length; i += 2) {
            result[j] = hexToByte(hex.substring(i, i + 2));
            ++j;
        }

        return result;
    }

    private static byte hexToByte(String hex) {
        return (byte) Integer.parseInt(hex, 16);
    }

    public static String bytesToHex(byte[] bytes) {
        if (bytes == null) {
            return null;
        } else {
            StringBuilder sb = new StringBuilder();
            byte[] var2 = bytes;
            int var3 = bytes.length;

            for (int var4 = 0; var4 < var3; ++var4) {
                byte aByte = var2[var4];
                String hex = Integer.toHexString(aByte & 255);
                if (hex.length() < 2) {
                    sb.append(0);
                }

                sb.append(hex);
            }

            return sb.toString();
        }
    }

    public static byte[] utf8ToArray(String str) {
        return str.getBytes(StandardCharsets.UTF_8);
    }

    public static String arrayToUtf8(byte[] arr) {
        return new String(arr, StandardCharsets.UTF_8);
    }

    private static Map<String, Object> getOptionsMap(Sm4Options sm4Options) {
        Map<String, Object> options = new HashMap<>();
        if (sm4Options == null) {
            return options;
        } else {
            String padding = sm4Options.getPadding();
            if (padding != null && !padding.trim().equals("")) {
                options.put("padding", padding);
            }

            String mode = sm4Options.getMode();
            if (mode != null && !mode.trim().equals("")) {
                options.put("mode", mode);
            }

            String iv = sm4Options.getIv();
            if (iv != null && !iv.trim().equals("")) {
                options.put("iv", iv);
            }

            return options;
        }
    }

    static {
        try {
            InputStream inputStream = Sm4.class.getClassLoader().getResourceAsStream("sm/sm4.js");
            ScriptEngine engine = (new ScriptEngineManager()).getEngineByName("nashorn");
            engine.eval(new BufferedReader(new InputStreamReader(inputStream)));
            invocable = (Invocable) engine;
        } catch (ScriptException var2) {
            ScriptException e = var2;
            e.printStackTrace();
        }

    }

}
